package com.wiscamp.ninechapters.problems.infrastructure.repositories;

import com.wiscamp.ninechapters.common.core.CollectionHelper;
import com.wiscamp.ninechapters.problems.domain.models.mistakes.Mistake;
import com.wiscamp.ninechapters.problems.domain.models.mistakes.MistakeQuantityBySetType;
import com.wiscamp.ninechapters.problems.domain.repositories.MistakeRepository;
import com.wiscamp.ninechapters.problems.infrastructure.converters.MistakeConverter;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.mistakes.MistakeMapper;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.mistakes.MistakeViewMapper;
import com.wiscamp.ninechapters.problems.infrastructure.po.mistakes.MistakePO;
import com.wiscamp.ninechapters.problems.infrastructure.po.mistakes.MistakeView;
import cube.ddd.aspect.HandleDataException;
import cube.ddd.common.query.PagedObjects;
import cube.ddd.common.query.PagedQuery;
import cube.ddd.domain.BaseRepository;
import cube.ddd.utils.PersistenceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.Objects;

@Repository
public class MistakeRepositoryImpl  extends BaseRepository implements MistakeRepository {

    private final MistakeMapper mistakeMapper;

    private final MistakeViewMapper mistakeViewMapper;

    public MistakeRepositoryImpl(MistakeMapper mistakeMapper, MistakeViewMapper mistakeViewMapper) {
        this.mistakeMapper = mistakeMapper;
        this.mistakeViewMapper = mistakeViewMapper;
    }


    // region mistake
    private MistakePO getMistakePO(@Min(0) long id) {
        return PersistenceUtils.findById(id, mistakeMapper::findById);
    }

    @HandleDataException
    public Mistake getMistake(@Min(0) long mistakeId) {
        return PersistenceUtils.findEntityById(mistakeId, mistakeViewMapper::findById,
                MistakeConverter.Instance::toMistakeByView);
    }

    @HandleDataException
    public Mistake saveMistake(Mistake mistake) {
        var newId = mistake.getMistakeId();
        if (mistake.getMistakeId() <= 0) {
            var newMistake = PersistenceUtils.createEntity(mistake, mistakeMapper::saveAndFlush,
                    MistakeConverter.Instance::toMistakePO, MistakeConverter.Instance::toMistake);
            newId = newMistake.getMistakeId();
        } else {
            var existedPO = getMistakePO(mistake.getMistakeId());
            if (existedPO == null) existedPO = new MistakePO();
            PersistenceUtils.updateEntity(mistake, existedPO, mistakeMapper::saveAndFlush,
                    MistakeConverter.Instance::toMistakePO, MistakeConverter.Instance::toMistake);
        }

        return getMistake(newId);
    }

    @HandleDataException
    public boolean deleteMistake(long mistakeId) {
        var mistake = getMistake(mistakeId);
        if (Objects.isNull(mistake)) return false;
        mistake.delete();
        saveMistake(mistake);
        return true;
    }

    public Mistake getMistake(long userId, long taskId, long setId, long problemId, long questionId) {
        var mistakeView = mistakeViewMapper.findMistake(userId, taskId, setId, problemId, questionId);
        if (Objects.isNull(mistakeView)) return null;
        return MistakeConverter.Instance.toMistakeByView(mistakeView);
    }

    @HandleDataException
    public PagedObjects<Mistake> getMistakesByQuery(@NotNull PagedQuery query) {
        PagedObjects<MistakeView> pagedObjects = PersistenceUtils.getPersistenceObjectsByQuery(query, mistakeViewMapper::findAll);
        return PersistenceUtils.convertPagedObjects(pagedObjects, MistakeConverter.Instance::toMistakeByView);
    }

    @HandleDataException
    public int getMistakesQuantityByUser(@Min(0) long userId) {
        return mistakeViewMapper.countMistakesQuantityByUser(userId);
    }

    @HandleDataException
    public Collection<MistakeQuantityBySetType> getGroupedMistakesQuantityBySetType(long userId) {
        return mistakeViewMapper.findGroupedMistakeQuantity(userId);
    }

    @HandleDataException
    public Collection<Mistake> getMistakesBySetType(@Min(0) long userId, @Min(0) long setTypeId) {
        var mistakeViews = mistakeViewMapper.findMistakesBySetType(userId, setTypeId);
        return CollectionHelper.convertToArrayList(mistakeViews, MistakeConverter.Instance::toMistakeByView);
    }

    @HandleDataException
    public Collection<Mistake> getMistakesByUser(@Min(0) long userId) {
        var mistakeViews = mistakeViewMapper.findMistakesByUser(userId);
        return CollectionHelper.convertToArrayList(mistakeViews, MistakeConverter.Instance::toMistakeByView);
    }
    // endregion
}
